/******************************************************************************* 
  Copyright (C), 1988-2020, zeno Tech. Co., Ltd.
  Description:   系统编码测试程序  
  Function List:     
  History:
    <wangmc -- 2014-09-26>  创建
*******************************************************************************/ 

/* ========================================================================== */ 
/*                              头文件区                                      */ 
/* ========================================================================== */

#include "mediaPriv.h"
#include "gpio.h"
#include "System.h"
#include "uvc.h"

#include "ScreenMirrorStream.h"
#include "VideoFileStream.h"

#include "PictureFileStream.h"
#include "SubscribeMsgDel.h"

#include "CurtainActManager.h"


#include "UsbHotPlug.h"

#include "UsbAVStream.h"

#include "ConfigCb.h"

#include "WlanService.h"

#include <vector>

#include "RoomsMatchTail.h"

#include "ExternalAudioEquipment.h"

#include "MediaTcpClient.h"

#include "mdns.h"

#include "ConfigApi.h"

#include "kafkaService.h"

#include "UsbInStream.h"

#include "DigitalSignageManager.h"

#include "CurtainManager.h"

#include "DiskManager.h"

#include "BgmListManager.h"

#include "HdmioutControlManager.h"

#include "Gui/GuiDisplay.h"

#include "HomeScreenManager.h"

/* ========================================================================== */ 
/*                           宏定义区                                         */ 
/* ========================================================================== */ 
#define SPEAKER_TEST_PATH "/user/etc/speakerTest.pcm"




#define MIHOYO_VERSION 0


/* ========================================================================== */ 
/*                          和类型定义区                                      */ 
/* ========================================================================== */ 


/* ========================================================================== */ 
/*                          全局变量定义区                                    */ 
/* ========================================================================== */ 
MEDIA_ctl_t mediaCtl_g;

using namespace Media;
/* ========================================================================== */ 
/*                          函数定义区                                        */ 
/* ========================================================================== */ 
extern "C" {
    extern void IpcSystemInit(void);
    extern int SYS_CheckHwid(void);
    extern int AUDIO_Init();
    extern void MdnsInit();

    extern int SYS_UsrInit(void);
    void VideoInit();
}

/*******************************************************************************
* 函数名  : main
* 描  述  : 
* 输  入  : 
* 输  出  : NULL
* 返回值  : 0  : 成功。 
*           -1: 失败。 
*******************************************************************************/
static int MEDIA_cfgInit(void)
{
    int ret = 0;
    int val = 0;
    MEDIA_cfg_t *pCfg;

    pCfg = &mediaCtl_g.cfg;

    /* audio */
    ret |= INI_KeyGetInt(CONFIG_PATH, "audio", "audioenable", &val);
    pCfg->audioInState = val;
    /* alg */
    ret |= INI_KeyGetInt(CONFIG_PATH, "alg", "aimode", &val);
    pCfg->aiMode = val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "alg", "speakertrack", &val);
    pCfg->speakTrackMode = val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "alg", "tracktime", &val);
    pCfg->zoomTimes = val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "alg", "splitcnt", &val);
    pCfg->maxSplitCnt = val;
    /* ispColor */
    ret |= INI_KeyGetInt(CONFIG_PATH, "ispColor", "brightness", &val);
    pCfg->videoColor.brightness = (char)val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "ispColor", "contrast", &val);
    pCfg->videoColor.contrast = (char)val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "ispColor", "saturation", &val);
    pCfg->videoColor.saturation = (char)val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "ispColor", "hue", &val);
    pCfg->videoColor.hue = (char)val;
    /* videoView */
    ret |= INI_KeyGetInt(CONFIG_PATH, "videoView", "mirror", &val);
    pCfg->inOptions.mirror = (char)val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "videoView", "flip", &val);
    pCfg->inOptions.flip = (char)val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "videoView", "rotate90", &val);
    pCfg->inOptions.rotate90 = (char)val;
    /* whiteBalance */
    ret |= INI_KeyGetInt(CONFIG_PATH, "whiteBalance", "mode", &val);
    pCfg->inOptions.whiteBalance = (char)val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "whiteBalance", "colortemp", &val);
    pCfg->inOptions.colorTemp = (ushort)val;
    /* exposure */
    ret |= INI_KeyGetInt(CONFIG_PATH, "exposure", "mode", &val);
    pCfg->inOptions.exposure = val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "exposure", "compensation", &val);
    pCfg->inOptions.compansation = (uchar)val;
    //ret |= INI_KeyGetInt(CONFIG_PATH, "exposure", "frequency", &val);
    //pCfg->inOptions.antiFlicker = (uchar)val;

    ret |= INI_KeyGetInt(CUSTOM_PATH, "custom", "exposure_frequency", &val);
    pCfg->inOptions.antiFlicker = (uchar)val;

    /* preset.0 */
    ret |= INI_KeyGetInt(CONFIG_PATH, "preset.0", "zoom", &val);
    pCfg->preset[0].zoomAbs = val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "preset.0", "pan", &val);
    pCfg->preset[0].panAbs = val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "preset.0", "tilt", &val);
    pCfg->preset[0].tiltAbs = val;

    /* preset.1 */
    ret |= INI_KeyGetInt(CONFIG_PATH, "preset.1", "zoom", &val);
    pCfg->preset[1].zoomAbs = val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "preset.1", "pan", &val);
    pCfg->preset[1].panAbs = val;
    ret |= INI_KeyGetInt(CONFIG_PATH, "preset.1", "tilt", &val);
    pCfg->preset[1].tiltAbs = val;

    ret |= INI_KeyGetInt(CONFIG_PATH, "osd", "mirror", &val);
    pCfg->osdMirror = val;

    ret |= INI_KeyGetInt(CONFIG_PATH, "privacy", "enable", &val);
    pCfg->privacy = val;

    pCfg->zoomAbs = 40;
    pCfg->panAbs = 0;
    pCfg->tiltAbs = 0;

    if (ret)
    {
        return -1;
    }
    
    return 0;
}

static void *MEDIA_WtdThd(void *parg)
{
    int count = 0;
    int haveHwid;

    prctl(PR_SET_NAME, __func__);
    LOG_PrintInfo("tid:%d\n", gettid());

    mediaCtl_g.isReboot = 0;
    startWatchDogTimer(21);

    while (1)
    {
        haveHwid = SYS_CheckHwid();
        if ((0 == haveHwid) && (1 == mediaCtl_g.uvcState))
        {
            count++;
        }
        
        if (count < 60)
        {
            resetWatchDogTimer();
        }

        if (1 == mediaCtl_g.isReboot)
        {
            startWatchDogTimer(3);
        }
        
        sleep(7);
    }
    
    return NULL;
}

static int MEDIA_WtdInit(void)
{
    int ret;
    pthread_t wtdThd;
    
    ret = pthread_create(&wtdThd, 0, MEDIA_WtdThd, NULL);
    if (ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        return -1;
    }

    return 0;
}

static void *MEDIA_LedProcessThd(void *arg)
{
    int *state = (int *)arg;
    LedState_t ledState;
    
    prctl(PR_SET_NAME, __func__);
    LOG_PrintInfo("tid:%d\n", gettid());
    
    memset(&ledState, 0, sizeof(ledState));
    
    ledState.ledId = 0;
    ledState.mode = 1;
    ledState.periodCnt = -1;
    ledState.strength = 300;
    
    while (1)
    {
        if (*state)
        {
            ledState.onColor.r = 255;
            ledState.onColor.g = 0;
            ledState.onColor.b = 0;
            SysLedSet(ledState);
            sleep(1);
            ledState.onColor.r = 0;
            ledState.onColor.g = 255;
            ledState.onColor.b = 0;
            SysLedSet(ledState);
            sleep(1);
            ledState.onColor.r = 0;
            ledState.onColor.g = 0;
            ledState.onColor.b = 255;
            SysLedSet(ledState);
            sleep(1);
            ledState.onColor.r = 255;
            ledState.onColor.g = 255;
            ledState.onColor.b = 0;
            SysLedSet(ledState);
            sleep(1);
            ledState.onColor.r = 0;
            ledState.onColor.g = 255;
            ledState.onColor.b = 255;
            SysLedSet(ledState);
            sleep(1);
            ledState.onColor.r = 255;
            ledState.onColor.g = 0;
            ledState.onColor.b = 255;
            SysLedSet(ledState);
            sleep(1);
            ledState.onColor.r = 255;
            ledState.onColor.g = 255;
            ledState.onColor.b = 255;
            SysLedSet(ledState);
            sleep(1);

            //*state = 0;
        }
        else
        {
            usleep(1000*40);
        }
    }

    return NULL;
}



#if 1
#include <sys/prctl.h>
#include <sys/uio.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/prctl.h>

#include <linux/netlink.h>
#include <sys/socket.h>
#include <sys/time.h>

struct _uevent {
    char *strs[30];
    int size;
};

#define UAC_UEVENT_EXTCON         "SUBSYSTEM=extcon"

#define UAC_UEVENT_HIDRAW		  "SUBSYSTEM=hidraw"
#define ROOMS_MATCH_TAIL_VIDPID   "0627:A6A0"
#define AUDIO_A15_VIDPID          "1FC9:8266"

#define UVC_UEVENT_CIDEO4LINUX        "SUBSYSTEM=video4linux"
#define UVC_UEVENT_CIDEO4LINUX_ADD 	  "ACTION=add"
#define UVC_UEVENT_CIDEO4LINUX_REMOVE "ACTION=remove"

#define UAC_UEVENT_AUDIO            "SUBSYSTEM=u_audio"
#define UAC_UEVENT_SET_INTERFACE    "USB_STATE=SET_INTERFACE"
#define UAC_UEVENT_SET_SAMPLE_RATE  "USB_STATE=SET_SAMPLE_RATE"
#define UAC_UEVENT_SET_VOLUME       "USB_STATE=SET_VOLUME"
#define UAC_UEVENT_SET_MUTE         "USB_STATE=SET_MUTE"
#define UAC_UEVENT_SET_AUDIO_CLK    "USB_STATE=SET_AUDIO_CLK"

#define UAC_STREAM_DIRECT           "STREAM_DIRECTION="
#define UAC_STREAM_STATE            "STREAM_STATE="
#define UAC_SAMPLE_RATE             "SAMPLE_RATE="
#define UAC_SET_VOLUME              "VOLUME="
#define UAC_SET_MUTE                "MUTE="
#define UAC_PPM                     "PPM="

#define UVC_IN_STATE      2
#define UVC_IN_ACTION     0
#define UVC_IN_NODE_INDEX 9

// remote device/pc->our device
#define UAC_REMOTE_PLAY     "OUT"

// our device->remote device/pc
#define UAC_REMOTE_CAPTURE  "IN"

// sound card is opened
#define UAC_STREAM_START    "ON"

// sound card is closed
#define UAC_STREAM_STOP     "OFF"

enum UAC_UEVENT_KEY {
    UAC_KEY_AUDIO = 2,
    UAC_KEY_USB_STATE = 3,
    UAC_KEY_DIRECTION = 4,
    UAC_KEY_PPM = 4,
    UAC_KEY_STREAM_STATE = 5,
    UAC_KEY_SAMPLE_RATE = UAC_KEY_STREAM_STATE,
    UAC_KEY_VOLUME      = UAC_KEY_STREAM_STATE,
    UAC_KEY_MUTE        = UAC_KEY_STREAM_STATE,
};

int compare(const char* dst, const char* srt) {
    if ((dst == NULL) || (srt == NULL))
        return 0;

    if (!strncmp(dst, srt, strlen(srt))) {
        return 1;
    }

    return 0;
}

/*
 * strs[0] = ACTION=change
 * strs[1] = DEVPATH=/devicges/virtual/u_audio/UAC1_Gadgeta 0
 * strs[2] = SUBSYSTEM=u_audio
 * strs[3] = USB_STATE=SET_VOLUME
 * strs[4] = STREAM_DIRECTION=OUT
 * strs[5] = VOLUME=72%
 */
void audio_set_volume(const struct _uevent *uevent) {
    char *direct = uevent->strs[UAC_KEY_DIRECTION];
    char *volumeStr = uevent->strs[UAC_KEY_VOLUME];
    LOG_PrintInfo("direct = %s volume = %s\n", direct, volumeStr);

    if (compare(direct, UAC_STREAM_DIRECT)) {
        char* device = &direct[strlen(UAC_STREAM_DIRECT)];
        int volume = 100;
        int vol;
        sscanf(volumeStr, "VOLUME=%d", &volume);
        if (compare(device, UAC_REMOTE_PLAY)) {
            LOG_PrintInfo("set volume %d to usb record\n", volume);
        #if 0     
            vol = volume/6;
            if (vol > 15)
            {
                vol = 15;
            }
            else if ((vol == 0) && (volume != 0))
            {
                vol = 1;
            }
            MEDIA_SetPlayVol(vol, 0);
        #endif
        

            MEDIA_UacVolumeFactorSet(volume);  
        
        } else if (compare(device, UAC_REMOTE_CAPTURE)) {
            LOG_PrintInfo("set volume %d to usb playback\n", volume);

        }
    }
}

/*
 * strs[0] = ACTION=change
 * strs[1] = DEVPATH=/devices/virtual/u_audio/UAC1_Gadget 0
 * strs[2] = SUBSYSTEM=u_audio
 * strs[3] = USB_STATE=SET_MUTE
 * strs[4] = STREAM_DIRECTION=OUT
 * strs[5] = MUTE=1
*/
void audio_set_mute(const struct _uevent *uevent) {
    char *direct = uevent->strs[UAC_KEY_DIRECTION];
    char *muteStr = uevent->strs[UAC_KEY_MUTE];
    LOG_PrintInfo("direct = %s mute = %s\n", direct, muteStr);

    if (compare(direct, UAC_STREAM_DIRECT)) {
        char* device = &direct[strlen(UAC_STREAM_DIRECT)];
        int mute = 0;
        sscanf(muteStr, "MUTE=%d", &mute);
        if (compare(device, UAC_REMOTE_PLAY)) {
            LOG_PrintInfo("set mute = %d to usb record\n", mute);
            // MEDIA_SetPlayVol(-1, mute);
        } else if (compare(device, UAC_REMOTE_CAPTURE)) {
            LOG_PrintInfo("set mute = %d to usb playback\n", mute);
          
        }
    }
}

void audio_play(const struct _uevent *uevent) {
    char *direct = uevent->strs[UAC_KEY_DIRECTION];
    char *status = uevent->strs[UAC_KEY_STREAM_STATE];

    if (compare(direct, UAC_STREAM_DIRECT) && compare(status, UAC_STREAM_STATE)) {
        char* device = &direct[strlen(UAC_STREAM_DIRECT)];
        char* state  = &status[strlen(UAC_STREAM_STATE)];
        // remote device/pc open/close usb sound card to write data
        if (compare(device, UAC_REMOTE_PLAY)) {
            if (compare(UAC_STREAM_START, state)) {
                // stream start, we need to open usb card to record datas
                LOG_PrintInfo("remote device/pc start to play data to us, we need to open usb to capture datas\n");
                
            } else if (compare(UAC_STREAM_STOP, state)) {
                LOG_PrintInfo("remote device/pc stop to play data to us, we need to stop capture datas\n");
                
            }
        } else if (compare(device, UAC_REMOTE_CAPTURE)) {
            // our device->remote device/pc
            if (compare(UAC_STREAM_START, state)) {
                // stream start, we need to open usb card to record datas
                //LOG_PrintInfo("remote device/pc start to record from us, we need to open usb to send datas\n");
                mediaCtl_g.recordState = 1;
            } else if (compare(UAC_STREAM_STOP, state)) {
                //LOG_PrintInfo("remote device/pc stop to record from us, we need to stop write datas to usb\n");
                mediaCtl_g.recordState = 0;
            }
        }
    }
}



void audio_event(const struct _uevent *uevent) {
    char *event = uevent->strs[UAC_KEY_USB_STATE];
    char *direct = uevent->strs[UAC_KEY_DIRECTION];
    char *status = uevent->strs[UAC_KEY_STREAM_STATE];

    if ((event == NULL) || (direct == NULL) || (status == NULL)) {
        return;
    }

    int setInterface = compare(event, UAC_UEVENT_SET_INTERFACE);
    int setSampleRate = compare(event, UAC_UEVENT_SET_SAMPLE_RATE);
    int setVolume = compare(event, UAC_UEVENT_SET_VOLUME);
    int setMute = compare(event, UAC_UEVENT_SET_MUTE);
    int setClk = compare(event, UAC_UEVENT_SET_AUDIO_CLK);
    if (!setInterface && !setSampleRate && !setVolume && !setMute && !setClk) {
        return;
    }

    if (setInterface) {
        audio_play(uevent);
    } else if(setSampleRate) {
        
    } else if(setVolume) {
        audio_set_volume(uevent);
    } else if(setMute) {
        audio_set_mute(uevent);
    }  else if(setClk) {
        
    }
}

#define BUS_USB_DEVICES "/proc/bus/usb/devices"
#define UEVENT_BUFFER_SIZE      2048          /* 热插拔信息接收缓存大小 */

#define USB_DWC3_PATH "/sys/devices/platform/ff4c0000.usb2-phy/extcon/extcon0/state"

static int USB_CheckConnect(void)
{
    int enable = 0;
    char *pStr;
    FILE *fp = NULL;
    char buff[128] = {0};

    fp = fopen(USB_DWC3_PATH, "r");
    if(!fp)
    {
        LOG_PrintError("Fail to open %s.\n", USB_DWC3_PATH);
        return -1;
    }

    fread(buff, 1, 128, fp);

    pStr = strstr(buff, "USB=");
    if (pStr)
    {
        sscanf(pStr, "USB=%d", &enable);
    }
    else
    {
        enable = 0;
    }

    fclose(fp);
    
    return enable;
}

int usb_connect(void)
{
    return mediaCtl_g.connState;
}

#if 0
static int connect_event(void)
{
    int connState;
    int status = -1;
    LedState_t ledState;
    memset(&ledState, 0, sizeof(ledState));

    static int initGpio = 0;
    int whiteLed = 20;
    int ledLevel = 1;
    if (0 == initGpio)
    {
        initGpio = 1;
        GPIO_Get(whiteLed);
        GPIO_SetDir(whiteLed, 1);
    }
    
    ledState.ledId = 0;
    ledState.mode = 1;
    ledState.periodCnt = -1;
    ledState.strength = 300;
    
    connState = USB_CheckConnect();

    LOG_PrintWarn("connState:%d\n", connState);

    if (SYS_CheckHwid() == 0)
    {
        mediaCtl_g.connState = 1;
    }
    else
    {
        mediaCtl_g.connState = connState;
    }

    if (0 == connState)
    {
        mediaCtl_g.uvcState = 0;
    }

    if (connState == 1)
    {
        ledState.onColor.r = 255;
        ledState.onColor.g = 255;
        ledState.onColor.b = 255;
        SysLedSet(ledState);
    #if 1
	    status = MEDIA_UvcInit();
	    if (status)
	    {
	        LOG_PrintError("Fail to init encode!\n");
	    }
	#endif
    }
    else if (connState == 0)
    {
        ledState.onColor.r = 255;
        ledState.onColor.g = 255;
        ledState.onColor.b = 0;
        SysLedSet(ledState);

		UVC_DeInit();
        if (0 == VIDEO_PlayStatus())
        {
            GPIO_SetLevel(whiteLed, !ledLevel);
        }
    }

    return 0;
}
#endif

static int connect_event(void)
{
#if 0
    LedState_t ledState;
    memset(&ledState, 0, sizeof(ledState));

    static int initGpio = 0;
    int whiteLed = 20;
    int ledLevel = 1;
    if (0 == initGpio)
    {
        initGpio = 1;
        GPIO_Get(whiteLed);
        GPIO_SetDir(whiteLed, 1);
    }


    ledState.ledId = 0;
    ledState.mode = 1;
    ledState.periodCnt = -1;
    ledState.strength = 300;
#endif

    int connState = USB_CheckConnect();

    LOG_PrintWarn("connState:%d\n", connState);

    if (SYS_CheckHwid() == 0)
    {
        mediaCtl_g.connState = 1;
    }
    else
    {
        mediaCtl_g.connState = connState;
    }

    if (0 == connState)
    {
        mediaCtl_g.uvcState = 0;

        Media::CurtainActManager::instance()->ctrlUsbVideo(false);
    }
#if 0
    if (connState == 1)
    {
        ledState.onColor.r = 255;
        ledState.onColor.g = 255;
        ledState.onColor.b = 255;
        SysLedSet(ledState);
    }
    else if (connState == 0)
    {
        ledState.onColor.r = 255;
        ledState.onColor.g = 255;
        ledState.onColor.b = 0;
        SysLedSet(ledState);

        if (0 == VIDEO_PlayStatus())
        {
            GPIO_SetLevel(whiteLed, !ledLevel);
        }
    }
#endif
    return 0;
}

static int addUsbDivice(char *info){
	//LOG_PrintInfo("info:%s\n", info);
	//解析出socket消息中的设备节点名称和PID,VID
	int getIpStatus = 0;
	std::vector<std::string> splitData = UsbHotPlug::stringSplit(info, '//');

	if(splitData.size() < 11){
		return -1;
	}
	string deviceNode = splitData[10];
	string usbport = splitData[6];
	
    if(strstr(splitData[8].c_str(), ROOMS_MATCH_TAIL_VIDPID) != NULL){
		RoomsMatchTail::instance()->openHidraw(usbport, deviceNode);
		//获取AP的ssid和keys
		Json::Value table;
		Json::Value apTable;
        ConfigApi::IConfigInterface::GetInstance()->Get("APInfo", apTable);
        if(!apTable.isMember("Password") || !apTable.isMember("Ssid")){
            LOG_PrintError("error get apinfo json\n");
            return -1;
        }
		table["k"] = apTable["Password"].asString();

		char snid[64] = {0};
		int status_get_snid = INI_KeyGetString(DEV_HARDWARE_PATH, "hardwareTest", "snid", snid);
		if(status_get_snid < 0){
			LOG_PrintError("openService get snid fail\n");
		}
		
		string sn = snid;		
		table["s"] = apTable["Ssid"].asString();
		//获取Bssid
		char macaddr[32] = {0};
		if(NetGetMAC("wlan1", macaddr, 32)){
			LOG_PrintError("Faild to get wlan1 macaddr\n");
			return -1;
		}
		table["b"] = macaddr;
        //获取信道下发
        int channel = -1;
        for(int i = 10; i < 100; i++){
            if(WlanService::instance()->getApChannel("/var/rtl_hostapd.conf", channel)){
                break;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
        }
        if(channel == -1){
            LOG_PrintError("Cannot get ap channel\n");
        }else{
            table["c"] = channel;
        }
		//下发
		RoomsMatchTail::instance()->sendMsgToTail(table, usbport);
		//开启场景
		Json::Value root2 = Json::Value::null;
	    root2["Number"] = RoomsDefaultMeeting;
	    root2["PlayMode"] = 0;
	    root2["Action"] = 1;
	    //CurtainActManager::instance()->setPlayStrategy(root2);		

	    LOG_PrintWarn("matchTail end\n");
	}else{
    #if defined(MODEL_ROOMS)
        ExternalAudioEquipment::instance()->openHidraw(usbport, deviceNode);
    #endif
    }
	
	return 0;
}

static int removeUsbDivice(char *info){
	std::vector<std::string> splitData = UsbHotPlug::stringSplit(info, '//');
	
	if(splitData.size() < 11){
		return -1;
	}

	string usbport = splitData[6];
	if(strstr(splitData[8].c_str(), ROOMS_MATCH_TAIL_VIDPID) != NULL){
		RoomsMatchTail::instance()->closeHidraw(usbport);
	}else if(strstr(splitData[8].c_str(), AUDIO_A15_VIDPID) != NULL){
        #if defined(MODEL_ROOMS)
            ExternalAudioEquipment::instance()->closeHidraw(usbport);
        #endif
    }
	
	return 0;
}



static void add_uvc_device(const struct _uevent *event, const bool method)
{
	char *device_node_name;
	int devicenum;
	device_node_name = strstr(event->strs[5], "video");
    string node_name = device_node_name;
    devicenum =  stoi(node_name.substr(5, node_name.length() - 5));
	if(UsbHotPlug::isTail(devicenum)){
		LOG_PrintWarn("UsbHotPlug::isTail: true\n");
		return ;
	}
	string usbname;
	string devicePath = event->strs[1];
	//LOG_PrintWarn("videoinfo: %s\n", event->strs[1]);
	std::vector<std::string> splitData = UsbHotPlug::stringSplit(devicePath, '//');
	usbname = splitData[6];
	if(!usbname.empty() && usbname.length() > 4){
		usbname =   "usb-" + usbname.substr(2, usbname.length() - 2);
	}
	
	if(method){
		UsbAVStream::instance() -> addDevice(usbname, UVCIN, devicenum);
	}else{
		UsbAVStream::instance() -> removeDevice(usbname, UVCIN);
	}
}

static void parse_event(const struct _uevent *event) {
    if (event->size <= 0)
        return;

#if 0
    for (int i = 0 ; i < 10; i++) {
        if (event->strs[i] != NULL) {
            LOG_PrintInfo("strs[%d] = %s\n", i, event->strs[i]);
        }
    }
#endif

    if (compare(event->strs[UAC_KEY_AUDIO], UAC_UEVENT_AUDIO)) {
        audio_event(event);
    }

    if (compare(event->strs[UAC_KEY_AUDIO], UAC_UEVENT_EXTCON)) {
        connect_event();
    }

    if (compare(event->strs[UVC_IN_STATE], UVC_UEVENT_CIDEO4LINUX)) {
    	if(compare(event->strs[UVC_IN_ACTION], UVC_UEVENT_CIDEO4LINUX_ADD)){
    		add_uvc_device(event, true);
		}
		if(compare(event->strs[UVC_IN_ACTION], UVC_UEVENT_CIDEO4LINUX_REMOVE)){
			add_uvc_device(event, false);
		}
    }else if(compare(event->strs[UVC_IN_STATE], UAC_UEVENT_HIDRAW)){
		if(compare(event->strs[UVC_IN_ACTION], UVC_UEVENT_CIDEO4LINUX_ADD)){
			//addUsbDivice(event->strs[1]);
		}
		if(compare(event->strs[UVC_IN_ACTION], UVC_UEVENT_CIDEO4LINUX_REMOVE)){
			//removeUsbDivice(event->strs[1]);
		}
	}
}

static void *MEDIA_HotPlugThd(void *arg)
{
    int sockfd;
    int i, j, len;
    char buf[1024 + 2];
    struct iovec iov;
    struct msghdr msg;
    struct sockaddr_nl sa;
    struct _uevent event;

    prctl(PR_SET_NAME, __func__);
    LOG_PrintInfo("tid:%d\n", gettid());

    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    sa.nl_groups = NETLINK_KOBJECT_UEVENT;
    sa.nl_pid = 0;
    memset(&msg, 0, sizeof(msg));
    iov.iov_base = (void *)buf;
    iov.iov_len = sizeof(buf);
    msg.msg_name = (void *)&sa;
    msg.msg_namelen = sizeof(sa);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    if (sockfd == -1) {
        LOG_PrintError("socket creating failed:%s\n", strerror(errno));
        goto err_event_monitor;
    }

    if (bind(sockfd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
        LOG_PrintError("bind error:%s\n", strerror(errno));
        goto err_event_monitor;
    }

    while (1) {
        event.size = 0;
        len = recvmsg(sockfd, &msg, 0);
        if (len < 0) {
            LOG_PrintError("receive error\n");
        } else if (len < 32 || len > sizeof(buf)) {
            LOG_PrintError("invalid message\n");
        } 
        else 
        {
            for (i = 0, j = 0; i < len; i++) 
            {
                if (*(buf + i) == '\0' && (i + 1) != len) 
                {
                    event.strs[j++] = buf + i + 1;
                    event.size = j;
                }
            }

            parse_event(&event);
        }
    }

err_event_monitor:
    pthread_detach(pthread_self());
    pthread_exit(NULL);
}


static int MEDIA_HotPlugCheck(void)
{
    int ret;
    pthread_t hotPlugThd;

    connect_event();

    //初始化usbstream管理，注册回调
    UsbInStream::instance(UsbAVStream::instance()->USB_IN_1);
    UsbInStream::instance(UsbAVStream::instance()->USB_IN_2);

    //首次获取UVC设备的信息，适用于开机tail就插着Tail
    UsbHotPlug::searchVideo();	

    ret = pthread_create(&hotPlugThd, 0, MEDIA_HotPlugThd, NULL);
    if (ret)
    {
        LOG_PrintError("can't create thread: %s\n", strerror(ret));
        return -1;
    }

    UsbHotPlug::instance();

    return 0;
}
#endif

static int CreatCheckMtd(void)
{
    int fd;
    
    fd = open("/mnt/mtd/Sys/checkMtd", O_RDWR | O_CREAT | O_TRUNC, 0644);
	if (fd < 0)
	{
	    LOG_PrintError("Fail to open /var/checkMtd.\n");
	    return -1;
	}

	close(fd);

	return 0;
}

static int MEDIA_NetWorkInit(void)
{
    int status = 0;
    int isDhcp = 0;
    char macaddrStr[32] = {0};
    char ipaddrStr[16] = {0};
    char netmaskStr[16] = {0};
    char gatewayStr[16] = {0};
    bool DhcpFlg = false;
    bool result = false;

#if defined(MODEL_ROOMS) || defined(MODEL_AIR)

    ///有线网络初始化
    status = INI_KeyGetString(INI_NETWORK_PATH, "network", "macaddr", macaddrStr);
    if (status)
    {
        LOG_PrintError("Fail to get usb ini key.\n");
        return -1;
    }

    if (strcmp(macaddrStr, "ff:ff:ff:ff:ff:ff") != 0)
    {
        if (NetSetMAC("eth0", macaddrStr))
        {
            LOG_PrintError("Set macaddr failed!\n");
        }
    }

    Json::Value netTable;
    WlanService::instance()->getWiredNetwork(netTable);
  
    result = WlanService::instance()->setWiredNetwork(netTable["IP"].asString(), netTable["Mask"].asString(), netTable["GateWay"].asString(), netTable["Dhcp"].asBool());
    
    if (!result)
    {
        LOG_PrintError("Fail to setWiredNetwork.\n");
    }
#endif

    ///无线网络初始化
	Json::Value wifiTable;
	ConfigApi::IConfigInterface::GetInstance()->Get("Wifi", wifiTable);		
	string ssid = wifiTable["SSID"].asString();
	string key	= wifiTable["key"].asString();
	string bssid =  wifiTable["Wifi"]["BSSID"].asString();

	result = WlanService::instance()->connectWifi(ssid, key, bssid, 5);	
    if (!result)
    {
        LOG_PrintError("Fail to connectWifi.\n");
    }

#if 0
    //读取配置文件直接赋值返回，硬件验证使用

    sleep(5);
	ifstream ifs;
	Json::Value table;
	Json::Reader reader;
	ifs.open("/mnt/sd/wifi");
	if (!reader.parse(ifs, table))
	{
		LOG_PrintError("faild to read json data from ifstream\n");
		return -1;
	}

	if(table.isMember("Wifi") 
	  && table["Wifi"].isMember("SSID")
	  && table["Wifi"].isMember("key"))
	{
        string ssid = table["Wifi"]["SSID"].asString();
    	string key	= table["Wifi"]["key"].asString();
        string bssid = table["Wifi"]["BSSID"].asString();
    	result = WlanService::instance()->connectWifi(ssid, key, bssid);	
        if (!result)
        {
            LOG_PrintError("Fail to connectWifi.\n");
            return -1;
        }
	}
	else
	{
		LOG_PrintError("Wifi param error\n");
		return -1;
	}

	

#endif

#if defined(MODEL_ROOMS) || defined(MODEL_AIR)
    
    result = WlanService::instance()->startDynamicRouteService();	
    if (!result)
    {
        LOG_PrintError("Fail to startDynamicRouteService.\n");
    }


	//首次获取Tail的信息，适用于开机tail就插着Tail
	auto lam = [](char *msg){
		addUsbDivice(msg);
		return true;
	};
	//RoomsMatchTail::instance()->FirstSearchTail(lam);
#endif

    return 0;
}

static void signal_handler(int signo)
{
	LOG_PrintWarn("Ignal SIG_PIPE signal\n");

	struct sigaction sa; //信号处理结构体
    memset(&sa, '\0', sizeof(sa));
    sa.sa_handler = SIG_IGN;//SIG_IGN宏代表的操作就是忽略该信号 
    sa.sa_flags = 0;
    if(sigaction(SIGPIPE, &sa, NULL))//将信号和信号的处理结构体绑定
        return;
}

static void sysLedControl()
{   
    if(!GuiDisplay::Instance()->LedStatusWarn()){
        LedColor_t color;
        color.r = 0;
        color.g = 255;
        color.b = 0;
        LedCnt::instance()->setStaticLed(color);
    }
 
}


static void registerProtocol(){
    DigitalSignageManager::Instance();
    CurtainManager::Instance();
    DiskManager::Instance();
    BgmListManager::Instance();
    HdmioutControlManager::Instance();
    HomeScreenManager::Instance();
}

int MediaLibRun(void)
{
    registerProtocol();   
    int status;

    //该接口需要优化掉，不应该在这里调用
	SYS_UsrInit();

	MEDIA_WtdInit();
	IpcSystemInit();
	pthread_mutex_init(&mediaCtl_g.algMutex, NULL);
	status = MEDIA_cfgInit();
	if (status)
    {
        LOG_PrintError("Fail to get ini cfg.\n");
        return -1;
    }

    CreatCheckMtd();	


#if defined(MODEL_ROOMS) || defined(MODEL_AIR)
    //http设置配置的回调注册，需要在启动HTTP服务之前调用
    ConfigCb::instance();
    
#endif

    Json::Value table;
#if defined(MODEL_ROOMS)
    table["device_type"] = "ROOMS";
#elif defined(MODEL_AIR)
    table["device_type"] = "AIR";
#endif 
    bool ret = ConfigApi::IConfigInterface::GetInstance()->Set("DeviceInfo", table, ConfigApi::ConfigOptions::ConfigOptionPart);


	mediaCtl_g.uvcChn = USBTYPEC_OUT;
	MEDIA_HotPlugCheck();
	VideoInit();
    // status = MEDIA_TransferInit();
    // if (status)
    // {
    //     LOG_PrintWarn("Fail to init transfer!\n");
    // }

	AUDIO_Init();

    status = MEDIA_UvcInit();
    if (status)
    {
        LOG_PrintError("Fail to init encode!\n");
        return -1;
    }
	status = MEDIA_HidInit();	
	if (status)
    {
        LOG_PrintError("Fail to init encode!\n");
        return -1;
    }

#if defined(MODEL_ROOMS) || defined(MODEL_AIR)

    status = MEDIA_RecorderInit();
    if (status < 0)
    {           
        LOG_PrintError("MEDIA_RecorderIniterror:\n");
        return -1;
    }
#endif

    // awi_dfu_module_init();
    // awi_dfu_module_start();
    MEDIA_NetWorkInit();  

#if defined(MODEL_ROOMS) || defined(MODEL_AIR)		
	MdnsInit();

	sleep(2); //等待SD卡挂载就绪
#endif

    CurtainActManager::instance()->playStartUpCurtain();

#if MIHOYO_VERSION
#if defined(MODEL_ROOMS)    
    kafkaService::instance()->startReportThd();
#endif    
#endif

#if defined(MODEL_ROOMS) || defined(MODEL_AIR)	
    sysLedControl();
#endif
    return 0;
}
